package hw1_magicSquare;

import ilog.concert.*;
import ilog.cplex.*;

public class magicSquare {
	public static void main(String[] args) throws IloException{
		int len = 4;
		int sum = 34;
		
		IloCplex model = new IloCplex();
		
		//define variables
		IloIntVar[][][] x = new IloIntVar[len][len][len*len];
		for(int i=0; i<len; i++) {
			for(int j=0; j<len; j++) {
				for(int k=0; k<len*len; k++) {
					x[i][j][k] = model.boolVar("X[" + i + "," + j + "," + k + "]");
				}
			}
		}
		
		//objective
		IloNumExpr obj = model.numExpr();
		//set the objective as 0
		obj = model.sum(obj, 0);
		
		//constraints1-each cell contains exactly one number
		for(int i=0; i<len; i++) {
			for(int j=0; j<len; j++) {
				IloLinearIntExpr expr1 = model.linearIntExpr();
				for(int k=0; k<len*len; k++) {
					expr1.addTerm(1, x[i][j][k]);
				}
				model.addEq(expr1, 1);
			}
		}
		
		//constraints2-each number 𝑘appears only once in a block
		for(int k=0; k<len*len; k++) {
			IloLinearIntExpr expr2 = model.linearIntExpr();
			for(int i=0; i<len; i++) {
				for(int j=0; j<len; j++) {
					expr2.addTerm(1, x[i][j][k]);
				}
			}
			model.addEq(expr2, 1);
		}
		
		//constraints3-each row adds up to 15
		for(int i=0; i<len; i++) {
			IloLinearIntExpr expr3 = model.linearIntExpr();
			for(int k=0; k<len*len; k++) {				
				for(int j=0; j<len; j++) {
					expr3.addTerm(k+1, x[i][j][k]);	
				}
				
			}
			model.addEq(expr3, sum);
		}

		//constraints4-each column adds up to 15
		for(int j=0; j<len; j++) {
			IloLinearIntExpr expr4 = model.linearIntExpr();
			for(int k=0; k<len*len; k++) {
				for(int i=0; i<len; i++) {
					expr4.addTerm(k+1, x[i][j][k]);	
				}
				
			}
			model.addEq(expr4, sum);
		}
		
		//constraints5-each positive diagonals adds up to 15
		IloLinearIntExpr expr5 = model.linearIntExpr();
		for(int k=0; k<len*len; k++) {
			for(int i=0; i<len; i++) {
				expr5.addTerm(k+1, x[i][i][k]);	
			}
		}
		model.addEq(expr5, sum);
		
		//constraints6-each off diagonals adds up to 15
		IloLinearIntExpr expr6 = model.linearIntExpr();
		for(int k=0; k<len*len; k++) {
			for(int i=0; i<len; i++) {
				expr6.addTerm(k+1, x[i][len-1-i][k]);	
			}
		}
		model.addEq(expr6, sum);

		//solve problem
		if (model.solve()) {
			model.output().println("Solution status = " + model.getStatus());
			model.output().println("Solution value = " + model.getObjValue());
			for(int i=0; i<len; i++) {
				for(int j=0; j<len; j++) {
					for(int k=0; k<len*len; k++) {
						if(model.getValue(x[i][j][k]) == 1) {
							System.out.println("X[" + i + "," + j + "] = " + (k+1));
						}
					}
				}
			}
		}
		model.close();
	}
}
